/************************************************

     Brian Bousquet-Smith     Chaz Godwin
	            
		    OBDII Reader
	             Fall 2011


NOTES:

Code designed for use on an ATMEGA164A AVR. If this
is not the chip being used unknown errors may be 
involved in the running of this code. 
************************************************/

#include <avr/io.h>
#include <avr/iom164.h> 
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "obd.h"
#include "lcd.h"

/************************************************
		     Defines
************************************************/

// States

#define ELM_INIT_STATE			1
#define	OBD_INIT_STATE			2
#define BLUETOOTH_INIT_STATE		3
#define DASHBOARD			4

// Error Defines

#define OK 				0
#define OVERFLOW			-1	
#define BAD_DATA			-2
#define NO_DEVICE_FOUND			-3
#define IMP_DATA			-4

/*
*	Error Meanings
*
*	Overflow - Buffer limit of 100 was reached before receiving an end of command byte 
*	Bad Data - Response from the OBDII wasn't the data expected as the reponse
*	No Device Found - Output when the ELM can't find an active protocol to communicate with

*	Unknown - This response isn't at all expected
*
*/

// Initializing Functions
 
void serial_init();
void print_bits(char byte);
void print_error(int error);

/************************************************
		Global Variables
************************************************/

//int main_state = BLUETOOTH_INIT_STATE;
int main_state = BLUETOOTH_INIT_STATE;

int main(void){

/*
*	Purpose: Output RPM and MPH data from a vehicle
*/	
	DDRA = 0xFF;
	serial_init();
	lcd_flush();
	unsigned char tmp;
	int mph;
	int rpm;
	int response = -1;	

/************************************************
		State Machine
************************************************/
	//_delay_ms(5000);
	//clear_lcd();
	PORTA = 0x00;
	while(1){
		switch(main_state){

		// Initialization States	

		case ELM_INIT_STATE: // Initializes ELM
			response = elm_init();
			if(response == OK){	
				main_state = OBD_INIT_STATE;
				break;
			}
			print_error(response);
			break;

		case OBD_INIT_STATE: // Initializes OBDII
			obd_flush();
			response = obd_init();
			if(response == OK){
				main_state = BLUETOOTH_INIT_STATE;				
				break;
			}
			print_error(response);
			break;

		case BLUETOOTH_INIT_STATE: // Initializes Bluetooth		

			response = bluetooth_init();	
			if(response == 0){
				//main_state = ELM_INIT_STATE;
				main_state = DASHBOARD;
				break;
			}
			print_error(response);
			break;	

		case DASHBOARD: // Virtual Dashboard			
			//mph = get_mph();			// Gets mph data (in Hex)
			//rpm = get_rpm();			// Gets rpm data (in Hex)
			mph = 100;
			rpm = 12345;
			if( (mph==IMP_DATA) || (rpm==IMP_DATA)){	// Impossible Data
				main_state = ELM_INIT_STATE;
				print_error(BAD_DATA);
				break;
			}	
			lcd_transmit(mph);			//	Transmits mph data
			lcd_transmit(rpm>>8);		// Transmits high byte of rpm
			lcd_transmit(rpm&0x00FF);	// Transmits low byte of rpm
			tmp = lcd_receive();		// Receives acknowledge byte
			if(tmp == '1') break;		// If the byte received isn't '1' then there is an error else break
			else{
				main_state =  BLUETOOTH_INIT_STATE;			
				print_error(BAD_DATA);
				break;
			}			
		} 
	}
	return 0;
}

void serial_init(){

/*
*	Purpose: Initialize Serial on Both UART Ports on the AVR
*	Input: Nothing
*	Output: Nothing
*/

// ELM

	UCSR0A |= (1<<U2X0);				// Double speed for more precision
	UCSR0B |= (1<<RXEN0)|(1<<TXEN0);	// Allow transmit and receive
	UCSR0C |= (0<<USBS0)|(3<<UCSZ00); 	// 8 Bit No Parity 1 Stop Bit
	UBRR0H = 0;							// Sets Baud Rate = 9600
	UBRR0L = 12;

// Bluetooth

	UCSR1A |= (1<<U2X1);				// Double speed for more precision
	UCSR1B |= (1<<RXEN1)|(1<<TXEN1); 	// Allow transmit and receive
	UCSR1C |= (0<<USBS1)|(3<<UCSZ10); 	// 8 Bit No Parity 1 Stop Bits
	UBRR1H = 0;							// Sets Baud Rate = 9600
	UBRR1L = 12;
}

void print_error(int error){

/*
*	Purpose: Print status of the program on the leds 
*	Input: Error wanting to be printed
*	Output: Nothing
*/

	PORTA = 0x03;
	char times = 0;	
	switch(error){	// Based on the error flashes LEDs
		case OVERFLOW:
			times = 1;
			break;
		case BAD_DATA:
			times = 2;
			break;
		case NO_DEVICE_FOUND:
			times = 3;
			break;
	}
	int i;
	for(i=0;i<times;i++){	// Flashes LEDs certain number of times
		PORTA = 0x00;
		_delay_ms(250);
		PORTA = 0x03;
		_delay_ms(250);
	}
}

void print_bits( char byte){

/*
*	Purpose: Print the bits of an ascii byte so that its easier to figure out what it is 
*	Input: Byte that needs to be written in bits
*	Output: Nothing
*/

	char mask[8] = {
	0b10000000,
	0b01000000,
	0b00100000,
	0b00010000,
	0b00001000,
	0b00000100,
	0b00000010,
	0b00000001};

	int m;
	char tmp;
	for(m=0;m<8;m++){	// Prints each bit to the leds either l/r for 0/1
		tmp = ((mask[m]&byte)>>(7-m))+1;
		PORTA = tmp;		
		_delay_ms(1000);
		PORTA = 0x00;
		_delay_ms(100);
	}
}	



